/*
 * main.cpp
 *
 *  Created on: Aug 26, 2011
 *      Author: Jon
 */

//	DDRB = _BV(PB0);//Pinmode(8, OUTPUT);
//	PORTB = _BV(PB0); //digitalWrite(8, HIGH);


#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <stdio.h>

extern "C" void __cxa_pure_virtual() { while (1); }

#include <uart.h>

#define delay(x) _delay_ms(x)
void delay_us(unsigned long delay)
{
	while(delay--) asm volatile("nop");
}

#define MOTOR_PORT PORTC
#define MOTOR_DDR DDRC

#define THREE_HOUR_PIN PC5
#define FIVE_HOUR_PIN PD6
#define SEVEN_HOUR_PIN PD7
#define NINE_HOUR_PIN PB0
#define TWELVE_HOUR_PIN	PB1
#define RELEASE_PIN PD5

#define RELEASE_INPUT_PORT PIND
#define FIVE_HOUR_INPUT_PORT PIND
#define SEVEN_HOUR_INPUT_PORT PIND
#define NINE_HOUR_INPUT_PORT PINB
#define TWELVE_HOUR_INPUT_PORT PINB

#define BAUD 115200UL


typedef enum TIMES
{
	THREE = 10799/*3*3600*/,
	FIVE = 18000/*5*3600*/,
	SEVEN = 25200/*7*3600*/,
	NINE = 32400/*9*3600*/,
	TWELVE = 43200/*12*3600*/
}TIMES;

void clear();
void setCoordinate(uint8_t x, uint8_t y);
void setPixel(uint8_t x, uint8_t y, uint8_t pixel_on);
void drawLine(uint8_t x, uint8_t y,uint8_t x1, uint8_t y1, uint8_t pixel_on);
uint8_t calculateTimeRemaining(uint32_t seconds, char * buff);

void setupTimer()
{
  //TCCR1A = _BV(COM1B1);
  TCCR1B = _BV(CS12)| _BV(CS10) | _BV(WGM12);//--CLK/1024 = 7812.5Hz
  /*Compare Match every 1 second*/
  uint16_t counts = 7813;//attiny88 = 1.000064 (1sec)
  OCR1B = counts;
  TIMSK1 = _BV(OCIE1B);
}


void step(uint8_t steps, uint8_t direction, volatile uint8_t * motor_pos)
{
  uint8_t motor_step[4] = {0x1a, 0x16, 0x15, 0x19};//full step
  //uint8_t motor_step[8] = {0x18, 0x1a, 0x12, 0x16, 0x14, 0x15, 0x11, 0x19};//half step
  uint8_t motor_position = *motor_pos;
  for(int i=0;i<steps;i++)
  {
    MOTOR_PORT = motor_step[motor_position];
    delay(20);  // delay time for each step
    if(direction)
    {
      motor_position++;
    }
    else
    {
      motor_position--;
    }
    motor_position = motor_position & 0x03;//full step
    //motor_position = motor_position & 0x07;//half step
  }
  *motor_pos = motor_position;
  MOTOR_PORT = 0x00;
}

volatile uint32_t seconds = 0; //Max time is: ~18 hours
volatile uint32_t time_delay = TWELVE;
volatile uint8_t motor_position = 0;
char buff[50];
int main(void)
{

	//Buttons
	DDRD &= ~_BV(RELEASE_PIN) | ~_BV(FIVE_HOUR_PIN) | ~_BV(SEVEN_HOUR_PIN);//inputs
	PORTD = _BV(RELEASE_PIN) | _BV(FIVE_HOUR_PIN) | _BV(SEVEN_HOUR_PIN);

	DDRB &= ~_BV(NINE_HOUR_PIN) | ~_BV(TWELVE_HOUR_PIN);
	PORTB = _BV(NINE_HOUR_PIN) | _BV(TWELVE_HOUR_PIN);

	//Motor Pins
	MOTOR_DDR = 0xff;//pinMode(0-7, OUTPUT);

	_delay_ms(500);

	cli();
	setupTimer();
	_delay_ms(500);

	uart_init(8 | 0x8000);
	_delay_ms(1000);
	clear();
	uart_puts("Kitteh Feeder...");
	setCoordinate(0,48);
	uart_puts("Set to 12 hours");
	delay(500);



	sei();
	uint16_t counter = 0;
	while(1)
	{
		if(bit_is_clear(FIVE_HOUR_INPUT_PORT, FIVE_HOUR_PIN))
		{
			time_delay = FIVE;
			setCoordinate(0,48);
			uart_puts("Set to 5 hours");
			while(bit_is_clear(PINC, FIVE_HOUR_PIN));
		}
		if(bit_is_clear(SEVEN_HOUR_INPUT_PORT,SEVEN_HOUR_PIN))
		{
			time_delay = SEVEN;
			setCoordinate(0,48);
			uart_puts("Set to 7 hours");
			while(bit_is_clear(PINC,SEVEN_HOUR_PIN));
		}
		if(bit_is_clear(NINE_HOUR_INPUT_PORT, NINE_HOUR_PIN))
		{
			time_delay = NINE;
			setCoordinate(0,48);
			uart_puts("Set to 9 hours");
			while(bit_is_clear(PINC, NINE_HOUR_PIN));
		}
		if(bit_is_clear(TWELVE_HOUR_INPUT_PORT, TWELVE_HOUR_PIN))
		{
			time_delay = TWELVE;
			setCoordinate(0,48);
			uart_puts("Set to 12 hours");
			while(bit_is_clear(PINC, TWELVE_HOUR_PIN));
		}
		if(bit_is_clear(RELEASE_INPUT_PORT, RELEASE_PIN))
		{
			//step(67, 1, &motor_position);//full step
			if(calculateTimeRemaining(time_delay-seconds,buff)>=6)
			{
				clear();
				uart_puts("No feeding.../n/rKitteh too fat");
			}
			else
			{
				step(33, 1, &motor_position);//half step
			}
		}
		if(counter++>16000)
		{
			calculateTimeRemaining(time_delay-seconds, buff);
			setCoordinate(16,16);
			uart_puts("Time Remaining:");
			setCoordinate(32,24);
			uart_puts(buff);
			counter =0;
		}
    }
	return 0;
}



ISR(TIMER1_COMPB_vect)
{
	seconds++;
	if(seconds>=time_delay)
	{
		step(67, 1, &motor_position);//full step
		//step(33, 1, &motor_position);//half step
		seconds = 0;
	}
	TCNT1=0;
}

uint8_t calculateTimeRemaining(uint32_t seconds, char * buff)
{
	uint16_t hours = seconds/3600;
	uint16_t minutes = (seconds-(hours*3600))/60;
	uint16_t sec = seconds-(hours*3600)-(minutes*60);
	sprintf(buff,"%2u:%2u:%2u", hours, minutes, sec);
	return hours;
}


void clear()
{
	uart_putc(0x7c);
	uart_putc(0x00);
	_delay_ms(250);
}

void setCoordinate(uint8_t x, uint8_t y)
{
	uart_putc(0x7c);
	uart_putc(0x18);
	uart_putc(x);

	uart_putc(0x7c);
	uart_putc(0x19);
	uart_putc(y);
	_delay_ms(250);
}

void setPixel(uint8_t x, uint8_t y, uint8_t pixel_on)
{
	uart_putc(0x7c);
	uart_putc(0x10);
	uart_putc(x);
	uart_putc(y);
	if(pixel_on)
	{
		uart_putc(0x01);
	}
	else
	{
		uart_putc(0x00);
	}
}

void drawLine(uint8_t x, uint8_t y,uint8_t x1, uint8_t y1, uint8_t pixel_on)
{
	uart_putc(0x7c);
	uart_putc(0x0c);
	uart_putc(x);
	uart_putc(y);
	uart_putc(x1);
	uart_putc(y1);
	if(pixel_on)
	{
		uart_putc(0x01);
	}
	else
	{
		uart_putc(0x00);
	}
}



